home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/env python
- # -*- coding: UTF-8 -*-
-
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of the GNU General Public License
- # as published by the Free Software Foundation; either version 2
- # of the License, or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- #
- # Authors: Quinn Storm (quinn@beryl-project.org)
- # Patrick Niklaus (marex@opencompositing.org)
- # Guillaume Seguin (guillaume@segu.in)
- # Christopher Williams (christopherw@verizon.net)
- # Copyright (C) 2007 Quinn Storm
-
- import pygtk
- import gtk
- import gtk.gdk
- import gobject
- import cairo, pangocairo
- from math import pi, sqrt
- import time
- import re
- import mimetypes
- mimetypes.init()
-
- from ccm.Utils import *
- from ccm.Constants import *
- from ccm.Conflicts import *
-
- import locale
- import gettext
- locale.setlocale(locale.LC_ALL, "")
- gettext.bindtextdomain("ccsm", DataDir + "/locale")
- gettext.textdomain("ccsm")
- _ = gettext.gettext
-
- #
- # Try to use gtk like coding style for consistency
- #
-
- # Cell Renderer for MultiList
-
- class CellRendererColor(gtk.GenericCellRenderer):
- __gproperties__ = {
- 'text': (gobject.TYPE_STRING,
- 'color markup text',
- 'The color as markup like this: #rrrrggggbbbbaaaa',
- '#0000000000000000',
- gobject.PARAM_READWRITE)
- }
-
- _text = '#0000000000000000'
- _color = [0, 0, 0, 0]
- _surface = None
- _surface_size = (-1, -1)
-
- def __init__(self):
- gtk.GenericCellRenderer.__init__(self)
-
- def _parse_color(self):
- color = gtk.gdk.color_parse(self._text[:-4])
- alpha = int("0x%s" % self._text[-4:], base=16)
- self._color = [color.red/65535.0, color.green/65535.0, color.blue/65535.0, alpha/65535.0]
-
- def do_set_property(self, property, value):
- if property.name == 'text':
- self._text = value
- self._parse_color()
-
- def do_get_property(self, property):
- if property.name == 'text':
- return self._text
-
- def on_get_size(self, widget, cell_area):
- return (0, 0, 0, 0) # FIXME
-
- def redraw(self, width, height):
- # found in gtk-color-button.c
- CHECK_SIZE = 4
- CHECK_DARK = 21845 # 65535 / 3
- CHECK_LIGHT = 43690
-
- width += 10
- height += 10
- self._surface_size = (width, height)
- self._surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
- cr = cairo.Context(self._surface)
-
- x = 0
- y = 0
- colors = [CHECK_DARK, CHECK_LIGHT]
- state = 0
- begin_state = 0
- while y < height:
- while x < width:
- cr.rectangle(x, y, CHECK_SIZE, CHECK_SIZE)
- c = colors[state] / 65535.0
- cr.set_source_rgb(c, c, c)
- cr.fill()
- x += CHECK_SIZE
- state = not state
- state = not begin_state
- begin_state = state
- x = 0
- y += CHECK_SIZE
-
- def on_render(self, window, widget, background_area, cell_area, expose_area, flags):
- cr = window.cairo_create()
-
- height, width = (cell_area.height, cell_area.width)
- sheight, swidth = self._surface_size
- if height > sheight or width > swidth:
- self.redraw(width, height)
-
- cr.rectangle(cell_area.x, cell_area.y, width, height)
- cr.clip()
-
- cr.set_source_surface(self._surface, cell_area.x, cell_area.y)
- cr.paint()
-
- r, g, b, a = self._color
- cr.set_source_rgba(r, g, b, a)
- cr.paint()
-
- class PluginView(gtk.TreeView):
- def __init__(self, plugins):
- liststore = gtk.ListStore(str, gtk.gdk.Pixbuf, bool, object)
- self.model = liststore.filter_new()
- gtk.TreeView.__init__(self, self.model)
-
- self.SelectionHandler = None
-
- self.Plugins = set(plugins)
-
- for plugin in sorted(plugins.values(), key=PluginKeyFunc):
- liststore.append([plugin.ShortDesc, Image(plugin.Name, type=ImagePlugin).props.pixbuf,
- plugin.Enabled, plugin])
-
- column = self.insert_column_with_attributes(0, _('Plugin'), gtk.CellRendererPixbuf(), pixbuf=1, sensitive=2)
- cell = gtk.CellRendererText()
- cell.props.wrap_width = 200
- column.pack_start(cell)
- column.set_attributes(cell, text=0)
- self.model.set_visible_func(self.VisibleFunc)
- self.get_selection().connect('changed', self.SelectionChanged)
-
- def VisibleFunc(self, model, iter):
- return model[iter][3].Name in self.Plugins
-
- def Filter(self, plugins):
- self.Plugins = set(plugins)
- self.model.refilter()
-
- def SelectionChanged(self, selection):
- model, iter = selection.get_selected()
- if iter is None:
- return self.SelectionHandler(None)
-
- return self.SelectionHandler(model[iter][3])
-
- class GroupView(gtk.TreeView):
- def __init__(self, name):
- self.model = gtk.ListStore(str, str)
- gtk.TreeView.__init__(self, self.model)
-
- self.SelectionHandler = None
-
- self.Visible = set()
-
- cell = gtk.CellRendererText()
- cell.props.ypad = 5
- cell.props.wrap_width = 200
- column = gtk.TreeViewColumn(name, cell, text=0)
- self.append_column(column)
-
- self.get_selection().connect('changed', self.SelectionChanged)
- self.hide_all()
- self.props.no_show_all = True
-
- def Update(self, items):
- self.model.clear()
-
- self.model.append([_('All'), 'All'])
-
- length = 0
- for item in items:
- self.model.append([item or _("General"), item])
- if item: # exclude "General" from count
- length += 1
-
- if length:
- self.show_all()
- self.props.no_show_all = False
- else:
- self.hide_all()
- self.props.no_show_all = True
-
- def SelectionChanged(self, selection):
- model, iter = selection.get_selected()
- if iter is None:
- return None
-
- return self.SelectionHandler(model[iter][1])
-
- # Selector Buttons
- #
- class SelectorButtons(gtk.HBox):
- def __init__(self):
- gtk.HBox.__init__(self)
- self.set_border_width(10)
- self.set_spacing(5)
- self.buttons = []
- self.arrows = []
-
- def clear_buttons(self):
- for widget in (self.arrows + self.buttons):
- widget.destroy()
-
- self.arrows = []
- self.buttons = []
-
- def add_button(self, label, callback):
- arrow = gtk.Arrow(gtk.ARROW_RIGHT, gtk.SHADOW_NONE)
- button = gtk.Button(label)
- button.set_relief(gtk.RELIEF_NONE)
- button.connect('clicked', self.on_button_clicked, callback)
- if self.get_children():
- self.pack_start(arrow, False, False)
- self.arrows.append(arrow)
- self.pack_start(button, False, False)
- self.buttons.append(button)
- self.show_all()
-
- def remove_button(self, pos):
- if pos > len(self.buttons)-1:
- return
- self.buttons[pos].destroy()
- self.buttons.remove(self.buttons[pos])
- if pos > 0:
- self.arrows[pos-1].destroy()
- self.arrows.remove(self.arrows[pos-1])
-
- def on_button_clicked(self, widget, callback):
- callback(selector=True)
-
- # Selector Box
- #
- class SelectorBox(gtk.ScrolledWindow):
- def __init__(self, backgroundColor):
- gtk.ScrolledWindow.__init__(self)
- self.viewport = gtk.Viewport()
- self.viewport.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(backgroundColor))
- self.props.hscrollbar_policy = gtk.POLICY_NEVER
- self.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
- self.box = gtk.VBox()
- self.box.set_spacing(5)
- self.viewport.add(self.box)
- self.add(self.viewport)
-
- def close(self):
- self.destroy()
- self.viewport.destroy()
- for button in self.box.get_children():
- button.destroy()
- self.box.destroy()
-
- def add_item(self, item, callback, markup="%s", image=None, info=None):
- button = gtk.Button()
- label = Label(wrap=170)
- text = protect_pango_markup(item)
- label.set_markup(markup % text or _("General"))
- labelBox = gtk.VBox()
- labelBox.set_spacing(5)
- labelBox.pack_start(label)
- if info:
- infoLabel = Label()
- infoLabel.set_markup("<span size='small'>%s</span>" % info)
- labelBox.pack_start(infoLabel)
- box = gtk.HBox()
- box.set_spacing(5)
- if image:
- box.pack_start(image, False, False)
- box.pack_start(labelBox)
- button.add(box)
- button.connect("clicked", callback, item)
- button.set_relief(gtk.RELIEF_NONE)
- self.box.pack_start(button, False, False)
-
- def clear_list(self):
- for button in self.box.get_children():
- button.destroy()
-
- def set_item_list(self, list, callback):
- self.clear_list()
- for item in list:
- self.add_item(item)
-
- self.box.show_all()
-
- # Scrolled List
- #
- class ScrolledList(gtk.ScrolledWindow):
- def __init__(self, name):
- gtk.ScrolledWindow.__init__(self)
-
- self.props.hscrollbar_policy = gtk.POLICY_NEVER
- self.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
-
- self.store = gtk.ListStore(gobject.TYPE_STRING)
-
- self.view = gtk.TreeView(self.store)
- self.view.set_headers_visible(True)
- self.view.insert_column_with_attributes(-1, name, gtk.CellRendererText(), text=0)
-
- self.set_size_request(300, 300)
-
- self.add(self.view)
-
- self.select = self.view.get_selection()
- self.select.set_mode(gtk.SELECTION_SINGLE)
-
- def get_list(self):
- values = []
- iter = self.store.get_iter_first()
- while iter:
- value = self.store.get(iter, 0)[0]
- if value != "":
- values.append(value)
- iter = self.store.iter_next(iter)
- return values
-
- def clear(self):
- self.store.clear()
-
- def append(self, value):
- iter = self.store.append()
- self.store.set(iter, 0, value)
-
- def set(self, pos, value):
- iter = self.store.get_iter(pos)
- self.store.set(iter, 0, value)
-
- def delete(self, b):
- selected_rows = self.select.get_selected_rows()[1]
- for path in selected_rows:
- iter = self.store.get_iter(path)
- self.store.remove(iter)
-
- def move_up(self, b):
- selected_rows = self.select.get_selected_rows()[1]
- if len(selected_rows) == 1:
- iter = self.store.get_iter(selected_rows[0])
- prev = self.store.get_iter_first()
- if not self.store.get_path(prev) == self.store.get_path(iter):
- while prev is not None and not self.store.get_path(self.store.iter_next(prev)) == self.store.get_path(iter):
- prev = self.store.iter_next(prev)
- self.store.swap(iter, prev)
-
- def move_down(self, b):
- selected_rows = self.select.get_selected_rows()[1]
- if len(selected_rows) == 1:
- iter = self.store.get_iter(selected_rows[0])
- next = self.store.iter_next(iter)
- if next is not None:
- self.store.swap(iter, next)
-
- # Button modifier selection widget
- #
- class ModifierSelector (gtk.DrawingArea):
-
- __gsignals__ = {"added" : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, [gobject.TYPE_STRING]),
- "removed" : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, [gobject.TYPE_STRING])}
-
- _current = []
-
- _base_surface = None
- _surface = None
-
- _x0 = 0
- _y0 = 12
- _width = 100
- _height = 50
-
- _font = "Sans 12 Bold"
-
- def __init__ (self, mods):
- '''Prepare widget'''
- super (ModifierSelector, self).__init__ ()
- self._current = mods.split ("|")
- modifier = "%s/modifier.png" % PixmapDir
- self._base_surface = cairo.ImageSurface.create_from_png (modifier)
- self.add_events (gtk.gdk.BUTTON_PRESS_MASK)
- self.connect ("expose_event", self.expose)
- self.connect ("button_press_event", self.button_press)
- self.set_size_request (200, 120)
-
- x0, y0, width, height = self._x0, self._y0, self._width, self._height
- self._modifiers = {
- "Shift" : (x0, y0),
- "Control" : (x0, y0 + height),
- "Super" : (x0 + width, y0),
- "Alt" : (x0 + width, y0 + height)
- }
-
- self._names = {
- "Control" : "Ctrl"
- }
-
- def set_current (self, value):
- self._current = value.split ("|")
- self.redraw (queue = True)
-
- def get_current (self):
- return "|".join (filter (lambda s: len (s) > 0, self._current))
- current = property (get_current, set_current)
-
- def draw (self, cr, width, height):
- '''The actual drawing function'''
- for mod in self._modifiers:
- x, y = self._modifiers[mod]
- if mod in self._names: text = self._names[mod]
- else: text = mod
- cr.set_source_surface (self._base_surface, x, y)
- cr.rectangle (x, y, self._width, self._height)
- cr.fill_preserve ()
- if mod in self._current:
- cr.set_source_rgb (0.3, 0.3, 0.3)
- self.write (cr, x + 23, y + 12, text)
- cr.set_source_rgb (0.5, 1, 0)
- else:
- cr.set_source_rgb (0, 0, 0)
- self.write (cr, x + 22, y + 11, text)
-
- def write (self, cr, x, y, text):
- cr.move_to (x, y)
- markup = '''<span font_desc="%s">%s</span>''' % (self._font, text)
- pcr = pangocairo.CairoContext (cr)
- layout = pcr.create_layout ()
- layout.set_markup (markup)
- pcr.show_layout (layout)
-
- def redraw (self, queue = False):
- '''Redraw internal surface'''
- alloc = self.get_allocation ()
- # Prepare drawing surface
- width, height = alloc.width, alloc.height
- self._surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, width, height)
- cr = cairo.Context (self._surface)
- # Clear
- cr.set_operator (cairo.OPERATOR_CLEAR)
- cr.paint ()
- cr.set_operator (cairo.OPERATOR_OVER)
- # Draw
- self.draw (cr, alloc.width, alloc.height)
- # Queue expose event if required
- if queue:
- self.queue_draw ()
-
- def expose (self, widget, event):
- '''Expose event handler'''
- cr = self.window.cairo_create ()
- if not self._surface:
- self.redraw ()
- cr.set_source_surface (self._surface)
- cr.rectangle (event.area.x, event.area.y,
- event.area.width, event.area.height)
- cr.clip ()
- cr.paint ()
- return False
-
- def in_rect (self, x, y, x0, y0, x1, y1):
- return x >= x0 and y >= y0 and x <= x1 and y <= y1
-
- def button_press (self, widget, event):
- x, y = event.x, event.y
- mod = ""
-
- for modifier in self._modifiers:
- x0, y0 = self._modifiers[modifier]
- if self.in_rect (x, y, x0, y0,
- x0 + self._width, y0 + self._height):
- mod = modifier
- break
-
- if not len (mod):
- return
- if mod in self._current:
- self._current.remove (mod)
- self.emit ("removed", mod)
- else:
- self._current.append (mod)
- self.emit ("added", mod)
- self.redraw (queue = True)
-
- # Edge selection widget
- #
- class EdgeSelector (gtk.DrawingArea):
-
- __gsignals__ = {"clicked" : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_PYOBJECT,))}
-
- _base_surface = None
- _surface = None
- _radius = 13
- _cradius = 20
- _coords = []
-
- def __init__ (self):
- '''Prepare widget'''
- super (EdgeSelector, self).__init__ ()
- background = "%s/display.png" % PixmapDir
- self._base_surface = cairo.ImageSurface.create_from_png (background)
- self.add_events (gtk.gdk.BUTTON_PRESS_MASK)
- self.connect ("expose_event", self.expose)
- self.connect ("button_press_event", self.button_press)
- self.set_size_request (196, 196)
-
- # Useful vars
- x0 = 16
- y0 = 24
- x1 = 181
- y1 = 133
- x2 = x0 + 39
- y2 = y0 + 26
- x3 = x1 - 39
- y3 = y1 - 26
- self._coords = (x0, y0, x1, y1, x2, y2, x3, y3)
-
- def draw (self, cr, width, height):
- '''The actual drawing function'''
- # Useful vars
- x0, y0, x1, y1, x2, y2, x3, y3 = self._coords
- cradius = self._cradius
- radius = self._radius
-
- cr.set_line_width(1.0)
-
- # Top left edge
- cr.new_path ()
- cr.move_to (x0, y0 + cradius)
- cr.line_to (x0, y0)
- cr.line_to (x0 + cradius, y0)
- cr.arc (x0, y0, cradius, 0, pi / 2)
- cr.close_path ()
- self.set_fill_color (cr, "TopLeft")
- cr.fill_preserve ()
- self.set_stroke_color (cr, "TopLeft")
- cr.stroke ()
- # Top right edge
- cr.new_path ()
- cr.move_to (x1, y0 + cradius)
- cr.line_to (x1, y0)
- cr.line_to (x1 - cradius, y0)
- cr.arc_negative (x1, y0, cradius, pi, pi/2)
- cr.close_path ()
- self.set_fill_color (cr, "TopRight")
- cr.fill_preserve ()
- self.set_stroke_color (cr, "TopRight")
- cr.stroke ()
- # Bottom left edge
- cr.new_path ()
- cr.move_to (x0, y1 - cradius)
- cr.line_to (x0, y1)
- cr.line_to (x0 + cradius, y1)
- cr.arc_negative (x0, y1, cradius, 2 * pi, 3 * pi / 2)
- cr.close_path ()
- self.set_fill_color (cr, "BottomLeft")
- cr.fill_preserve ()
- self.set_stroke_color (cr, "BottomLeft")
- cr.stroke ()
- # Bottom right edge
- cr.new_path ()
- cr.move_to (x1, y1 - cradius)
- cr.line_to (x1, y1)
- cr.line_to (x1 - cradius, y1)
- cr.arc (x1, y1, cradius, pi, 3 * pi / 2)
- cr.close_path ()
- self.set_fill_color (cr, "BottomRight")
- cr.fill_preserve ()
- self.set_stroke_color (cr, "BottomRight")
- cr.stroke ()
- # Top edge
- cr.new_path ()
- cr.move_to (x2 + radius, y0)
- cr.line_to (x3 - radius, y0)
- cr.arc (x3 - radius, y0, radius, 0, pi / 2)
- cr.line_to (x2 + radius, y0 + radius)
- cr.arc (x2 + radius, y0, radius, pi / 2, pi)
- cr.close_path ()
- self.set_fill_color (cr, "Top")
- cr.fill_preserve ()
- self.set_stroke_color (cr, "Top")
- cr.stroke ()
- # Bottom edge
- cr.new_path ()
- cr.move_to (x2 + radius, y1)
- cr.line_to (x3 - radius, y1)
- cr.arc_negative (x3 - radius, y1, radius, 0, - pi / 2)
- cr.line_to (x2 + radius, y1 - radius)
- cr.arc_negative (x2 + radius, y1, radius, - pi / 2, pi)
- cr.close_path ()
- self.set_fill_color (cr, "Bottom")
- cr.fill_preserve ()
- self.set_stroke_color (cr, "Bottom")
- cr.stroke ()
- # Left edge
- cr.new_path ()
- cr.move_to (x0, y2 + radius)
- cr.line_to (x0, y3 - radius)
- cr.arc_negative (x0, y3 - radius, radius, pi / 2, 0)
- cr.line_to (x0 + radius, y2 + radius)
- cr.arc_negative (x0, y2 + radius, radius, 0, 3 * pi / 2)
- cr.close_path ()
- self.set_fill_color (cr, "Left")
- cr.fill_preserve ()
- self.set_stroke_color (cr, "Left")
- cr.stroke ()
- # Right edge
- cr.new_path ()
- cr.move_to (x1, y2 + radius)
- cr.line_to (x1, y3 - radius)
- cr.arc (x1, y3 - radius, radius, pi / 2, pi)
- cr.line_to (x1 - radius, y2 + radius)
- cr.arc (x1, y2 + radius, radius, pi, 3 * pi / 2)
- cr.close_path ()
- self.set_fill_color (cr, "Right")
- cr.fill_preserve ()
- self.set_stroke_color (cr, "Right")
- cr.stroke ()
-
- def set_fill_color (self, cr, edge):
- '''Set painting color for edge'''
- cr.set_source_rgb (0.9, 0.9, 0.9)
-
- def set_stroke_color (self, cr, edge):
- '''Set stroke color for edge'''
- cr.set_source_rgb (0.45, 0.45, 0.45)
-
- def redraw (self, queue = False):
- '''Redraw internal surface'''
- alloc = self.get_allocation ()
- # Prepare drawing surface
- width, height = alloc.width, alloc.height
- self._surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, width, height)
- cr = cairo.Context (self._surface)
- # Draw background
- cr.set_source_surface (self._base_surface)
- cr.paint ()
- # Draw
- self.draw (cr, alloc.width, alloc.height)
- # Queue expose event if required
- if queue:
- self.queue_draw ()
-
- def expose (self, widget, event):
- '''Expose event handler'''
- cr = self.window.cairo_create ()
- if not self._surface:
- self.redraw ()
- cr.set_source_surface (self._surface)
- cr.rectangle (event.area.x, event.area.y,
- event.area.width, event.area.height)
- cr.clip ()
- cr.paint ()
- return False
-
- def in_circle_quarter (self, x, y, x0, y0, x1, y1, x2, y2, radius):
- '''Args:
- x, y = point coordinates
- x0, y0 = center coordinates
- x1, y1 = circle square top left coordinates
- x2, y2 = circle square bottom right coordinates
- radius = circle radius'''
- if not self.in_rect (x, y, x1, y1, x2, y2):
- return False
- return self.dist (x, y, x0, y0) <= radius
-
- def dist (self, x1, y1, x2, y2):
- return sqrt ((x2 - x1) ** 2 + (y2 - y1) ** 2)
-
- def in_rect (self, x, y, x0, y0, x1, y1):
- return x >= x0 and y >= y0 and x <= x1 and y <= y1
-
- def button_press (self, widget, event):
- x, y = event.x, event.y
- edge = ""
-
- # Useful vars
- x0, y0, x1, y1, x2, y2, x3, y3 = self._coords
- cradius = self._cradius
- radius = self._radius
-
- if self.in_circle_quarter (x, y, x0, y0, x0, y0,
- x0 + cradius, y0 + cradius,
- cradius):
- edge = "TopLeft"
- elif self.in_circle_quarter (x, y, x1, y0, x1 - cradius, y0,
- x1, y0 + cradius, cradius):
- edge = "TopRight"
- elif self.in_circle_quarter (x, y, x0, y1, x0, y1 - cradius,
- x0 + cradius, y1, cradius):
- edge = "BottomLeft"
- elif self.in_circle_quarter (x, y, x1, y1, x1 - cradius, y1 - cradius,
- x1, y1, cradius):
- edge = "BottomRight"
- elif self.in_rect (x, y, x2 + radius, y0, x3 - radius, y0 + radius) \
- or self.in_circle_quarter (x, y, x2 + radius, y0, x2, y0,
- x2 + radius, y0 + radius, radius) \
- or self.in_circle_quarter (x, y, x3 - radius, y0, x3 - radius, y0,
- x3, y0 + radius, radius):
- edge = "Top"
- elif self.in_rect (x, y, x2 + radius, y1 - radius, x3 - radius, y1) \
- or self.in_circle_quarter (x, y, x2 + radius, y1, x2, y1 - radius,
- x2 + radius, y1, radius) \
- or self.in_circle_quarter (x, y, x3 - radius, y1,
- x3 - radius, y1 - radius,
- x3, y1, radius):
- edge = "Bottom"
- elif self.in_rect (x, y, x0, y2 + radius, x0 + radius, y3 - radius) \
- or self.in_circle_quarter (x, y, x0, y2 + radius, x0, y2,
- x0 + radius, y2 + radius, radius) \
- or self.in_circle_quarter (x, y, x0, y3 - radius,
- x0, y3 - radius,
- x0 + radius, y3, radius):
- edge = "Left"
- elif self.in_rect (x, y, x1 - radius, y2 + radius, x1, y3 - radius) \
- or self.in_circle_quarter (x, y, x1, y2 + radius, x1 - radius, y2,
- x1, y2 + radius, radius) \
- or self.in_circle_quarter (x, y, x1, y3 - radius,
- x1 - radius, y3 - radius,
- x1, y3, radius):
- edge = "Right"
-
- if edge:
- self.emit ("clicked", edge, event)
-
- # Edge selection widget
- #
- class SingleEdgeSelector (EdgeSelector):
-
- _current = []
-
- def __init__ (self, edge):
- '''Prepare widget'''
- EdgeSelector.__init__ (self)
- self._current = edge.split ("|")
- self.connect ('clicked', self.edge_clicked)
-
- def set_current (self, value):
- self._current = value.split ("|")
- self.redraw (queue = True)
-
- def get_current (self):
- return "|".join (filter (lambda s: len (s) > 0, self._current))
- current = property (get_current, set_current)
-
- def set_fill_color (self, cr, edge):
- '''Set painting color for edge'''
- if edge in self._current:
- cr.set_source_rgb (0.64, 1.0, 0.09)
- else:
- cr.set_source_rgb (0.80, 0.00, 0.00)
-
- def set_stroke_color (self, cr, edge):
- '''Set stroke color for edge'''
- if edge in self._current:
- cr.set_source_rgb (0.31, 0.60, 0.02)
- else:
- cr.set_source_rgb (0.64, 0.00, 0.00)
-
- def edge_clicked (self, widget, edge, event):
- if not len (edge):
- return
- if edge in self._current:
- self._current.remove (edge)
- else:
- self._current.append (edge)
-
- self.redraw (queue = True)
-
- # Global Edge Selector
- #
- class GlobalEdgeSelector(EdgeSelector):
-
- _settings = []
- _edges = {}
- _text = {}
- _context = None
-
- def __init__ (self, context, settings=[]):
- EdgeSelector.__init__ (self)
-
- self._context = context
- self._settings = settings
-
- self.connect ("clicked", self.show_popup)
-
- if len (settings) <= 0:
- self.generate_setting_list ()
-
- def set_fill_color (self, cr, edge):
- '''Set painting color for edge'''
- if edge in self._edges:
- cr.set_source_rgb (0.64, 1.0, 0.09)
- else:
- cr.set_source_rgb (0.80, 0.00, 0.00)
-
- def set_stroke_color (self, cr, edge):
- '''Set stroke color for edge'''
- if edge in self._edges:
- cr.set_source_rgb (0.31, 0.60, 0.02)
- else:
- cr.set_source_rgb (0.64, 0.00, 0.00)
-
- def set_settings (self, value):
- self._settings = value
-
- def get_settings (self):
- return self._settings
- settings = property (get_settings, set_settings)
-
- def generate_setting_list (self):
- self._settings = []
-
- def filter_settings(plugin):
- if plugin.Enabled:
- settings = sorted (GetSettings(plugin), key=SettingKeyFunc)
- settings = filter (lambda s: s.Type == 'Edge', settings)
- return settings
- return []
-
- for plugin in self._context.Plugins.values ():
- self._settings += filter_settings (plugin)
-
- for setting in self._settings:
- edges = setting.Value.split ("|")
- for edge in edges:
- self._edges[edge] = setting
-
- def set_edge_setting (self, setting, edge):
- if not setting:
- if edge in self._edges:
- self._edges.pop(edge)
- for setting in self._settings:
- value = setting.Value.split ("|")
- if edge in value:
- value.remove(edge)
- value = "|".join (filter (lambda s: len (s) > 0, value))
- setting.Value = value
- else:
- value = setting.Value.split ("|")
- if not edge in value:
- value.append (edge)
- value = "|".join (filter (lambda s: len (s) > 0, value))
-
- conflict = EdgeConflict (setting, value, settings = self._settings, autoResolve = True)
- if conflict.Resolve (GlobalUpdater):
- setting.Value = value
- self._edges[edge] = setting
-
- self._context.Write()
- self.redraw (queue = True)
-
- def show_popup (self, widget, edge, event):
- self._text = {}
- comboBox = gtk.combo_box_new_text ()
-
- comboBox.append_text (_("None"))
- comboBox.set_active (0)
- i = 1
- for setting in self._settings:
- text = "%s: %s" % (setting.Plugin.ShortDesc, setting.ShortDesc)
- comboBox.append_text (text)
- self._text[text] = setting
-
- if edge in setting.Value.split ("|"):
- comboBox.set_active (i)
- i += 1
-
- comboBox.set_size_request (200, -1)
- comboBox.connect ('changed', self.combo_changed, edge)
-
- popup = Popup (self, child=comboBox, decorated=False, mouse=True, modal=False)
- popup.show_all()
- popup.connect ('focus-out-event', self.focus_out)
-
- def focus_out (self, widget, event):
- combo = widget.get_child ()
- if combo.props.popup_shown:
- return
- gtk_process_events ()
- widget.destroy ()
-
- def combo_changed (self, widget, edge):
- text = widget.get_active_text ()
- setting = None
- if text != _("None"):
- setting = self._text[text]
- self.set_edge_setting (setting, edge)
- popup = widget.get_parent ()
- popup.destroy ()
-
- # Popup
- #
- class Popup (gtk.Window):
-
- def __init__ (self, parent=None, text=None, child=None, decorated=True, mouse=False, modal=True):
- gtk.Window.__init__ (self, gtk.WINDOW_TOPLEVEL)
- self.set_type_hint (gtk.gdk.WINDOW_TYPE_HINT_UTILITY)
- self.set_position (mouse and gtk.WIN_POS_MOUSE or gtk.WIN_POS_CENTER_ALWAYS)
- if parent:
- self.set_transient_for (parent.get_toplevel ())
- self.set_modal (modal)
- self.set_decorated (decorated)
- self.set_property("skip-taskbar-hint", True)
- if text:
- label = gtk.Label (text)
- align = gtk.Alignment ()
- align.set_padding (20, 20, 20, 20)
- align.add (label)
- self.add (align)
- elif child:
- self.add (child)
- gtk_process_events ()
-
- def destroy (self):
- gtk.Window.destroy (self)
- gtk_process_events ()
-
- # Key Grabber
- #
- class KeyGrabber (gtk.Button):
-
- __gsignals__ = {"changed" : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE,
- [gobject.TYPE_INT, gobject.TYPE_INT]),
- "current-changed" : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE,
- [gobject.TYPE_INT, gobject.TYPE_INT])}
-
- key = 0
- mods = 0
- handler = None
- popup = None
-
- label = None
-
- def __init__ (self, key = 0, mods = 0, label = None):
- '''Prepare widget'''
- super (KeyGrabber, self).__init__ ()
-
- self.key = key
- self.mods = mods
-
- self.label = label
-
- self.connect ("clicked", self.begin_key_grab)
- self.set_label ()
-
- def begin_key_grab (self, widget):
- self.add_events (gtk.gdk.KEY_PRESS_MASK)
- self.popup = Popup (self, _("Please press the new key combination"))
- self.popup.show_all()
- self.handler = self.popup.connect ("key-press-event",
- self.on_key_press_event)
- while gtk.gdk.keyboard_grab (self.popup.window) != gtk.gdk.GRAB_SUCCESS:
- time.sleep (0.1)
-
- def end_key_grab (self):
- gtk.gdk.keyboard_ungrab (gtk.get_current_event_time ())
- self.popup.disconnect (self.handler)
- self.popup.destroy ()
-
- def on_key_press_event (self, widget, event):
- mods = event.state & gtk.accelerator_get_default_mod_mask ()
-
- if event.keyval in (gtk.keysyms.Escape, gtk.keysyms.Return) \
- and not mods:
- if event.keyval == gtk.keysyms.Escape:
- self.emit ("changed", self.key, self.mods)
- self.end_key_grab ()
- self.set_label ()
- return
-
- key = gtk.gdk.keyval_to_lower (event.keyval)
- if (key == gtk.keysyms.ISO_Left_Tab):
- key = gtk.keysyms.Tab
-
- if gtk.accelerator_valid (key, mods) \
- or (key == gtk.keysyms.Tab and mods):
- self.set_label (key, mods)
- self.end_key_grab ()
- self.key = key
- self.mods = mods
- self.emit ("changed", self.key, self.mods)
- return
-
- self.set_label (key, mods)
-
- def set_label (self, key = None, mods = None):
- if self.label:
- if key != None and mods != None:
- self.emit ("current-changed", key, mods)
- gtk.Button.set_label (self, self.label)
- return
- if key == None and mods == None:
- key = self.key
- mods = self.mods
- label = gtk.accelerator_name (key, mods)
- if not len (label):
- label = _("Disabled")
- gtk.Button.set_label (self, label)
-
- # Match Button
- #
- class MatchButton(gtk.Button):
-
- __gsignals__ = {"changed" : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE,
- [gobject.TYPE_STRING])}
-
- prefix = {\
- _("Window Title"): 'title',
- _("Window Role"): 'role',
- _("Window Name"): 'name',
- _("Window Class"): 'class',
- _("Window Type"): 'type',
- _("Window ID"): 'xid',
- }
-
- symbols = {\
- _("And"): '&',
- _("Or"): '|'
- }
-
- match = None
-
- def __init__ (self, entry = None):
- '''Prepare widget'''
- super (MatchButton, self).__init__ ()
-
- self.entry = entry
- self.match = entry.get_text()
-
- self.add (Image (name = gtk.STOCK_ADD, type = ImageStock,
- size = gtk.ICON_SIZE_BUTTON))
- self.connect ("clicked", self.run_edit_dialog)
-
- def set_match (self, value):
- self.match = value
- self.entry.set_text(value)
- self.entry.activate()
-
- def get_xprop (self, regexp, proc = "xprop"):
- proc = os.popen (proc)
- output = proc.readlines ()
- rex = re.compile (regexp)
- value = ""
- for line in output:
- if rex.search (line):
- m = rex.match (line)
- value = m.groups () [-1]
- break
-
- return value
-
- # Regular Expressions taken from beryl-settings
- def grab_value (self, widget, value_widget, type_widget):
- value = ""
- prefix = self.prefix[type_widget.get_active_text()]
-
- if prefix == "type":
- value = self.get_xprop("^_NET_WM_WINDOW_TYPE\(ATOM\) = _NET_WM_WINDOW_TYPE_(\w+)")
- value = value.lower().capitalize()
- elif prefix == "role":
- value = self.get_xprop("^WM_WINDOW_ROLE\(STRING\) = \"([^\"]+)\"")
- elif prefix == "name":
- value = self.get_xprop("^WM_CLASS\(STRING\) = \"([^\"]+)\"")
- elif prefix == "class":
- value = self.get_xprop("^WM_CLASS\(STRING\) = \"([^\"]+)\", \"([^\"]+)\"")
- elif prefix == "title":
- value = self.get_xprop("^_NET_WM_NAME\(UTF8_STRING\) = ([^\n]+)")
- if value:
- list = value.split(", ")
- value = ""
- for hex in list:
- value += "%c" % int(hex, 16)
- else:
- value = self.get_xprop("^WM_NAME\(STRING\) = \"([^\"]+)\"")
- elif prefix == "id":
- value = self.get_xprop("^xwininfo: Window id: ([^\s]+)", "xwininfo")
-
- value_widget.set_text(value)
-
- def generate_match (self, type, value, relation, invert):
- match = ""
- text = self.match
-
- prefix = self.prefix[type]
- symbol = self.symbols[relation]
-
- # check if the current match needs some brackets
- if len(text) > 0 and text[-1] != ')' and text[0] != '(':
- match = "(%s)" % text
- else:
- match = text
-
- if invert:
- match = "%s %s !(%s=%s)" % (match, symbol, prefix, value)
- elif len(match) > 0:
- match = "%s %s %s=%s" % (match, symbol, prefix, value)
- else:
- match = "%s=%s" % (prefix, value)
-
- self.set_match (match)
-
- def _check_entry_value (self, entry, dialog):
- is_valid = False
- value = entry.get_text()
- if value != "":
- is_valid = True
- dialog.set_response_sensitive(gtk.RESPONSE_OK, is_valid)
-
- def run_edit_dialog (self, widget):
- '''Run dialog to generate a match'''
-
- self.match = self.entry.get_text ()
-
- dlg = gtk.Dialog (_("Edit match"))
- dlg.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
- dlg.set_transient_for (self.get_parent ().get_toplevel ())
- dlg.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
- dlg.add_button (gtk.STOCK_ADD, gtk.RESPONSE_OK).grab_default ()
- dlg.set_response_sensitive(gtk.RESPONSE_OK, False)
- dlg.set_default_response (gtk.RESPONSE_OK)
-
- table = gtk.Table ()
-
- rows = []
-
- # Type
- label = Label (_("Type"))
- type_chooser = gtk.combo_box_new_text ()
- for type in self.prefix.keys ():
- type_chooser.append_text (type)
- type_chooser.set_active (0)
- rows.append ((label, type_chooser))
-
- # Value
- label = Label (_("Value"))
- box = gtk.HBox ()
- box.set_spacing (5)
- entry = gtk.Entry ()
- entry.connect ('changed', self._check_entry_value, dlg)
- button = gtk.Button (_("Grab"))
- button.connect ('clicked', self.grab_value, entry, type_chooser)
- box.pack_start (entry, True, True)
- box.pack_start (button, False, False)
- rows.append ((label, box))
-
- # Relation
- label = Label (_("Relation"))
- relation_chooser = gtk.combo_box_new_text ()
- for relation in self.symbols.keys ():
- relation_chooser.append_text (relation)
- relation_chooser.set_active (0)
- rows.append ((label, relation_chooser))
-
- # Invert
- label = Label (_("Invert"))
- check = gtk.CheckButton ()
- rows.append ((label, check))
-
- row = 0
- for label, widget in rows:
- table.attach(label, 0, 1, row, row+1, yoptions=0, xpadding=TableX, ypadding=TableY)
- table.attach(widget, 1, 2, row, row+1, yoptions=0, xpadding=TableX, ypadding=TableY)
- row += 1
-
- dlg.vbox.pack_start (table)
- dlg.vbox.set_spacing (5)
- dlg.show_all ()
-
- response = dlg.run ()
- dlg.destroy ()
- if response == gtk.RESPONSE_OK:
- type = type_chooser.get_active_text ()
- value = entry.get_text ()
- relation = relation_chooser.get_active_text ()
- invert = check.get_active ()
- self.generate_match (type, value, relation, invert)
-
- class FileButton (gtk.Button):
- __gsignals__ = {"changed" : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE,
- [gobject.TYPE_STRING])}
- _directory = False
- _context = None
- _image = False
- _path = ""
-
- def __init__ (self, context, entry, directory=False, image=False, path=""):
- gtk.Button.__init__ (self)
-
- self._entry = entry
- self._directory = directory
- self._context = context
- self._image = image
- self._path = path
-
- self.set_tooltip_text(_("Browse..."))
- self.set_image(gtk.image_new_from_stock(
- gtk.STOCK_OPEN, gtk.ICON_SIZE_BUTTON))
- self.connect('clicked', self.open_dialog)
-
- def set_path (self, value):
- self._path = value
- self._entry.set_text (value)
- self._entry.activate ()
-
- def create_filter(self):
- filter = gtk.FileFilter ()
- if self._image:
- filter.set_name (_("Images"))
- filter.add_pattern ("*.png")
- filter.add_pattern ("*.jpg")
- filter.add_pattern ("*.jpeg")
- filter.add_pattern ("*.svg")
- else:
- filter.add_pattern ("*")
- filter.set_name (_("File"))
-
- return filter
-
- def check_type (self, filename):
- if filename.find (".") == -1:
- return True
- ext = filename.split (".") [-1]
-
- try:
- mime = mimetypes.types_map [".%s" %ext]
- except KeyError:
- return True
-
- if self._image:
- require = FeatureRequirement (self._context, 'imagemime:' + mime)
- return require.Resolve ()
-
- return True
-
- def update_preview (self, widget):
- path = widget.get_preview_filename ()
- if path is None or os.path.isdir (path):
- widget.get_preview_widget ().set_from_file (None)
- return
- try:
- pixbuf = gtk.gdk.pixbuf_new_from_file_at_size (path, 128, 128)
- except gobject.GError:
- return
- widget.get_preview_widget ().set_from_pixbuf (pixbuf)
-
- def open_dialog (self, widget):
- b = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)
- if self._directory:
- title = _("Open directory...")
- else:
- title = _("Open file...")
-
- chooser = gtk.FileChooserDialog (title = title, buttons = b)
- if self._directory:
- chooser.set_action (gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
- else:
- chooser.set_filter (self.create_filter ())
-
- if self._path and os.path.exists (self._path):
- chooser.set_filename (self._path)
- else:
- chooser.set_current_folder (os.environ.get("HOME"))
-
- if self._image:
- chooser.set_use_preview_label (False)
- chooser.set_preview_widget (gtk.Image ())
- chooser.connect ("selection-changed", self.update_preview)
-
- ret = chooser.run ()
-
- filename = chooser.get_filename ()
- chooser.destroy ()
- if ret == gtk.RESPONSE_OK:
- if self._directory or self.check_type (filename):
- self.set_path (filename)
-
- # About Dialog
- #
- class AboutDialog (gtk.AboutDialog):
- def __init__ (self, parent):
- gtk.AboutDialog.__init__ (self)
- self.set_transient_for (parent)
-
- self.set_name (_("CompizConfig Settings Manager"))
- self.set_version (Version)
- self.set_comments (_("This is a settings manager for the CompizConfig configuration system."))
- self.set_copyright ("Copyright \xC2\xA9 2007-2008 Patrick Niklaus/Christopher Williams/Guillaume Seguin/Quinn Storm")
- self.set_translator_credits (_("translator-credits"))
- self.set_authors (["Patrick Niklaus <marex@opencompositing.org>",
- "Christopher Williams <christopherw@verizon.net>",
- "Guillaume Seguin <guillaume@segu.in>",
- "Quinn Storm <quinn@beryl-project.org>"])
- self.set_artists (["Andrew Wedderburn <andrew.wedderburn@gmail.com>",
- "Patrick Niklaus <marex@opencompositing.org>",
- "Gnome Icon Theme Team"])
- if IconTheme.lookup_icon("ccsm", 64, 0):
- icon = IconTheme.load_icon("ccsm", 64, 0)
- self.set_logo (icon)
- self.set_website ("http://www.compiz-fusion.org")
-
- # Error dialog
- #
- class ErrorDialog (gtk.MessageDialog):
- '''Display an error dialog'''
-
- def __init__ (self, parent, message):
- gtk.MessageDialog.__init__ (self, parent,
- gtk.DIALOG_DESTROY_WITH_PARENT,
- gtk.MESSAGE_ERROR,
- gtk.BUTTONS_CLOSE)
- self.set_position (gtk.WIN_POS_CENTER)
- self.set_markup (message)
- self.set_title (_("An error has occured"))
- self.set_transient_for (parent)
- self.set_modal (True)
- self.show_all ()
- self.connect ("response", lambda *args: self.destroy ())
-
- # Warning dialog
- #
- class WarningDialog (gtk.MessageDialog):
- '''Display a warning dialog'''
-
- def __init__ (self, parent, message):
- gtk.MessageDialog.__init__ (self, parent,
- gtk.DIALOG_DESTROY_WITH_PARENT,
- gtk.MESSAGE_WARNING,
- gtk.BUTTONS_YES_NO)
- self.set_position (gtk.WIN_POS_CENTER)
- self.set_markup (message)
- self.set_title (_("Warning"))
- self.set_transient_for (parent)
- self.connect_after ("response", lambda *args: self.destroy ())
-
- # Plugin Button
- #
- class PluginButton (gtk.HBox):
-
- __gsignals__ = {"clicked" : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE,
- []),
- "activated" : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE,
- [])}
-
- _plugin = None
-
- def __init__ (self, plugin, useMissingImage = False):
- gtk.HBox.__init__(self)
- self._plugin = plugin
-
- image = Image (plugin.Name, ImagePlugin, 32, useMissingImage)
- label = Label (plugin.ShortDesc, 120)
- label.connect ('style-set', self.style_set)
- box = gtk.HBox ()
- box.set_spacing (5)
- box.pack_start (image, False, False)
- box.pack_start (label)
-
- button = PrettyButton ()
- button.connect ('clicked', self.show_plugin_page)
- button.set_tooltip_text (plugin.LongDesc)
- button.add (box)
-
- if plugin.Name != 'core':
- enable = gtk.CheckButton ()
- enable.set_tooltip_text(_("Enable %s") % plugin.ShortDesc)
- enable.set_active (plugin.Enabled)
- enable.set_sensitive (plugin.Context.AutoSort)
- self._toggled_handler = enable.connect ("toggled", self.enable_plugin)
- PluginSetting (plugin, enable, self._toggled_handler)
- self.pack_start (enable, False, False)
- self.pack_start (button, False, False)
-
- self.set_size_request (220, -1)
-
- StyleBlock = 0
-
- def style_set (self, widget, previous):
- if self.StyleBlock > 0:
- return
- self.StyleBlock += 1
- widget.modify_fg(gtk.STATE_NORMAL, widget.style.text[gtk.STATE_NORMAL])
- self.StyleBlock -= 1
-
- def enable_plugin (self, widget):
-
- plugin = self._plugin
- conflicts = plugin.Enabled and plugin.DisableConflicts or plugin.EnableConflicts
-
- conflict = PluginConflict (plugin, conflicts)
-
- if conflict.Resolve ():
- plugin.Enabled = widget.get_active ()
- else:
- widget.handler_block(self._toggled_handler)
- widget.set_active (plugin.Enabled)
- widget.handler_unblock(self._toggled_handler)
-
- plugin.Context.Write ()
- GlobalUpdater.UpdatePlugins()
- plugin.Context.UpdateExtensiblePlugins ()
- self.emit ('activated')
-
- def show_plugin_page (self, widget):
- self.emit ('clicked')
-
- def filter (self, text, level=FilterAll):
- found = False
- if level & FilterName:
- if (text in self._plugin.Name.lower ()
- or text in self._plugin.ShortDesc.lower ()):
- found = True
- if not found and level & FilterLongDesc:
- if text in self._plugin.LongDesc.lower():
- found = True
- if not found and level & FilterCategory:
- if text == None \
- or (text == "" and self._plugin.Category.lower() == "") \
- or (text != "" and text in self._plugin.Category.lower()):
- found = True
-
- return found
-
- def get_plugin (self):
- return self._plugin
-
- # Category Box
- #
- class CategoryBox(gtk.VBox):
-
- _plugins = None
- _unfiltered_plugins = None
- _buttons = None
- _context = None
- _name = ""
- _tabel = None
- _alignment = None
- _current_cols = 0
- _current_plugins = 0
-
- def __init__ (self, context, name, plugins=None, categoryIndex=0):
- gtk.VBox.__init__ (self)
-
- self.set_spacing (5)
-
- self._context = context
- if plugins is not None:
- self._plugins = plugins
- else:
- self._plugins = []
-
- if not plugins:
- for plugin in context.Plugins.values ():
- if plugin.Category == name:
- self._plugins.append (plugin)
-
- self._plugins.sort(key=PluginKeyFunc)
- self._name = name
- text = name or 'Uncategorized'
-
- # Keep unfiltered list of plugins for correct background icon loading
- self._unfiltered_plugins = self._plugins
-
- header = gtk.HBox ()
- header.set_border_width (5)
- header.set_spacing (10)
- label = Label ('', -1)
- label.set_markup ("<span color='#aaa' size='x-large' weight='800'>%s</span>" % _(text))
-
- icon = text.lower ().replace (" ", "_")
- image = Image (icon, ImageCategory)
- header.pack_start (image, False, False)
- header.pack_start (label, False, False)
-
- self._table = gtk.Table ()
- self._table.set_border_width (10)
-
- # load icons now only for the first 3 categories
- dontLoadIcons = (categoryIndex >= 3);
-
- self._buttons = []
- for plugin in self._plugins:
- button = PluginButton(plugin, dontLoadIcons)
- self._buttons.append(button)
-
- self._alignment = gtk.Alignment (0, 0, 1, 1)
- self._alignment.set_padding (0, 20, 0, 0)
- self._alignment.add (gtk.HSeparator ())
-
- self.pack_start (header, False, False)
- self.pack_start (self._table, False, False)
- self.pack_start (self._alignment)
-
- def show_separator (self, show):
- children = self.get_children ()
- if show:
- if self._alignment not in children:
- self.pack_start (self._alignment)
- else:
- if self._alignment in children:
- self.remove(self._alignment)
-
- def filter_buttons (self, text, level=FilterAll):
- self._plugins = []
- for button in self._buttons:
- if button.filter (text, level=level):
- self._plugins.append (button.get_plugin())
-
- return bool(self._plugins)
-
- def rebuild_table (self, ncols, force = False):
- if (not force and ncols == self._current_cols
- and len (self._plugins) == self._current_plugins):
- return
- self._current_cols = ncols
- self._current_plugins = len (self._plugins)
-
- children = self._table.get_children ()
- if children:
- for child in children:
- self._table.remove(child)
-
- row = 0
- col = 0
- for button in self._buttons:
- if button.get_plugin () in self._plugins:
- self._table.attach (button, col, col+1, row, row+1, 0, xpadding=TableX, ypadding=TableY)
- col += 1
- if col == ncols:
- col = 0
- row += 1
- self.show_all ()
-
- def get_buttons (self):
- return self._buttons
-
- def get_plugins (self):
- return self._plugins
-
- def get_unfiltered_plugins (self):
- return self._unfiltered_plugins
-
- # Plugin Window
- #
- class PluginWindow(gtk.ScrolledWindow):
- __gsignals__ = {"show-plugin" : (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE,
- [gobject.TYPE_PYOBJECT])}
-
- _not_found_box = None
- _style_block = 0
- _context = None
- _categories = None
- _viewport = None
- _boxes = None
- _box = None
-
- def __init__ (self, context, categories=[], plugins=[]):
- gtk.ScrolledWindow.__init__ (self)
-
- self._categories = {}
- self._boxes = []
- self._context = context
- pool = plugins or self._context.Plugins.values()
- if len (categories):
- for plugin in pool:
- category = plugin.Category
- if category in categories:
- if not category in self._categories:
- self._categories[category] = []
- self._categories[category].append(plugin)
- else:
- for plugin in pool:
- category = plugin.Category
- if not category in self._categories:
- self._categories[category] = []
- self._categories[category].append(plugin)
-
- self.props.hscrollbar_policy = gtk.POLICY_NEVER
- self.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
- self.connect ('size-allocate', self.rebuild_boxes)
-
- self._box = gtk.VBox ()
- self._box.set_spacing (5)
-
- self._not_found_box = NotFoundBox ()
-
- categories = sorted(self._categories, key=CategoryKeyFunc)
- for (i, category) in enumerate(categories):
- plugins = self._categories[category]
- category_box = CategoryBox(context, category, plugins, i)
- self.connect_buttons (category_box)
- self._boxes.append (category_box)
- self._box.pack_start (category_box, False, False)
-
- viewport = gtk.Viewport ()
- viewport.connect("style-set", self.set_viewport_style)
- viewport.set_focus_vadjustment (self.get_vadjustment ())
- viewport.add (self._box)
- self.add (viewport)
-
- def connect_buttons (self, category_box):
- buttons = category_box.get_buttons ()
- for button in buttons:
- button.connect('clicked', self.show_plugin_page)
-
- def set_viewport_style (self, widget, previous):
- if self._style_block > 0:
- return
- self._style_block += 1
- widget.modify_bg(gtk.STATE_NORMAL, widget.style.base[gtk.STATE_NORMAL])
- self._style_block -= 1
-
- def filter_boxes (self, text, level=FilterAll):
- found = False
-
- for box in self._boxes:
- found |= box.filter_buttons (text, level)
-
- viewport = self.get_child ()
- child = viewport.get_child ()
-
- if not found:
- if child is not self._not_found_box:
- viewport.remove (self._box)
- viewport.add (self._not_found_box)
- self._not_found_box.update (text)
- else:
- if child is self._not_found_box:
- viewport.remove (self._not_found_box)
- viewport.add (self._box)
-
- self.queue_resize()
- self.show_all()
-
- def rebuild_boxes (self, widget, request):
- ncols = request.width / 220
- width = ncols * (220 + 2 * TableX) + 40
- if width > request.width:
- ncols -= 1
-
- pos = 0
- last_box = None
- children = self._box.get_children ()
- for box in self._boxes:
- plugins = box.get_plugins ()
- if len (plugins) == 0:
- if box in children:
- self._box.remove(box)
- else:
- if last_box:
- last_box.show_separator (True)
-
- if box not in children:
- self._box.pack_start (box, False, False)
- self._box.reorder_child (box, pos)
- box.rebuild_table (ncols)
- box.show_separator (False)
- pos += 1
-
- last_box = box
-
- def get_categories (self):
- return self._categories.keys ()
-
- def show_plugin_page (self, widget):
- plugin = widget.get_plugin ()
- self.emit ('show-plugin', plugin)
-
-